package com.ckfinder.connector;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ckfinder.connector.configuration.Configuration;
import com.ckfinder.connector.configuration.ConfigurationFactory;
import com.ckfinder.connector.configuration.Constants;
import com.ckfinder.connector.configuration.Events.EventTypes;
import com.ckfinder.connector.configuration.IConfiguration;
import com.ckfinder.connector.data.BeforeExecuteCommandEventArgs;
import com.ckfinder.connector.errors.ConnectorException;
import com.ckfinder.connector.handlers.command.Command;
import com.ckfinder.connector.handlers.command.CopyFilesCommand;
import com.ckfinder.connector.handlers.command.CreateFolderCommand;
import com.ckfinder.connector.handlers.command.DeleteFilesCommand;
import com.ckfinder.connector.handlers.command.DeleteFolderCommand;
import com.ckfinder.connector.handlers.command.DownloadFileCommand;
import com.ckfinder.connector.handlers.command.ErrorCommand;
import com.ckfinder.connector.handlers.command.FileUploadCommand;
import com.ckfinder.connector.handlers.command.GetFilesCommand;
import com.ckfinder.connector.handlers.command.GetFoldersCommand;
import com.ckfinder.connector.handlers.command.IPostCommand;
import com.ckfinder.connector.handlers.command.InitCommand;
import com.ckfinder.connector.handlers.command.LoadCookiesCommand;
import com.ckfinder.connector.handlers.command.MoveFilesCommand;
import com.ckfinder.connector.handlers.command.QuickUploadCommand;
import com.ckfinder.connector.handlers.command.RenameFileCommand;
import com.ckfinder.connector.handlers.command.RenameFolderCommand;
import com.ckfinder.connector.handlers.command.ThumbnailCommand;
import com.ckfinder.connector.handlers.command.XMLCommand;
import com.ckfinder.connector.handlers.command.XMLErrorCommand;
import com.ckfinder.connector.utils.AccessControlUtil;
public class ConnectorServlet extends HttpServlet {
    private static final long serialVersionUID = 2960665641425153638L;
    @Override
    protected void doGet(final HttpServletRequest request,
                         final HttpServletResponse response) throws ServletException,
            IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        getResponse(request, response, false);
    }
    @Override
    protected void doPost(final HttpServletRequest request,
                          final HttpServletResponse response) throws ServletException,
            IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        getResponse(request, response, true);
    }
    private void createResouceTypesData(final Element rootElement) throws Exception {
        //resurcetypes
        Element element = creator.getDocument().createElement("ResourceTypes");
        rootElement.appendChild(element);
        List<String> types = null;
        if (super.type != null && !super.type.equals("")) {
            types = new ArrayList<String>();
            types.add(super.type);
        } else {
            types = getTypes();
        }
        for (String key : types) {
            ResourceType resourceType = configuration.getTypes().get(key);
            if (((this.type == null || this.type.equals(key)) && resourceType != null)&& AccessControlUtil.getInstance(this.configuration).checkFolderACL(key,"/",this.userRole,
                    AccessControlUtil.CKFINDER_CONNECTOR_ACL_FOLDER_VIEW)) {
                Element childElement = creator.getDocument().
                        createElement("ResourceType");
                childElement.setAttribute("name", resourceType.getName());
                childElement.setAttribute("acl", String.valueOf(
                        AccessControlUtil.getInstance(configuration).checkACLForRole(key,"/",this.userRole)));
                childElement.setAttribute("hash", randomHash(
                        resourceType.getPath()));
                childElement.setAttribute(
                        "allowedExtensions",
                        resourceType.getAllowedExtensions());
                childElement.setAttribute(
                        "deniedExtensions",
                        resourceType.getDeniedExtensions());
                childElement.setAttribute("url", resourceType.getUrl() + "/");
                Long maxSize = resourceType.getMaxSize();
                childElement.setAttribute("maxSize", (maxSize != null && maxSize > 0)  maxSize.toString() : "0");
                childElement.setAttribute("hasChildren",					FileUtils.hasChildren("/",newFile(PathUtils.escape(resourceType.getPath())),
                        configuration, resourceType.getName(), this.userRole).toString());
                element.appendChild(childElement);
            }
        }
    }
    private void getResponse(final HttpServletRequest request,
                             final HttpServletResponse response, final boolean post)
            throws ServletException {
        if (startException != null
                && Boolean.valueOf(getServletConfig().getInitParameter("debug"))) {
            throw new ServletException(startException);
        }
        String command = request.getParameter("command");
        IConfiguration configuration = null;
        try {
            configuration = ConfigurationFactory.getInstace().getConfiguration(request);
            if (configuration == null) {
                throw new Exception("Configuration wasn't initialized correctly. Check server logs.");
            }
        } catch (Exception e) {
            if (Boolean.valueOf(getServletConfig().getInitParameter("debug"))) {
                e.printStackTrace();
            }
            throw new ServletException(e);
        }
        try {
            if (command == null || command.equals("")) {
                throw new ConnectorException(
                        Constants.Errors.CKFINDER_CONNECTOR_ERROR_INVALID_COMMAND, false);
            }
            configuration.setDebugMode(
                    Boolean.valueOf(getServletConfig().getInitParameter("debug")));
            CommandHandlerEnum cmd = null;
            try {
                cmd = CommandHandlerEnum.valueOf(command.toUpperCase());
                // checks if command should go via POST request or it's a post request
                // and it's not upload command
                if ((cmd.getCommand() instanceof IPostCommand || post)
                        && !CommandHandlerEnum.FILEUPLOAD.equals(cmd)
                        && !CommandHandlerEnum.QUICKUPLOAD.equals(cmd)) {
                    checkPostRequest(request);
                }
            } catch (IllegalArgumentException e1) {
                //Ignore custom plugins commands
            }
            BeforeExecuteCommandEventArgs args = new BeforeExecuteCommandEventArgs();
            args.setCommand(command);
            args.setRequest(request);
            args.setResponse(response);
            if (configuration.getEvents() != null) {
                if (configuration.getEvents().run(EventTypes.BeforeExecuteCommand,
                        args, configuration)) {
                    cmd = CommandHandlerEnum.valueOf(command.toUpperCase());
                    cmd.execute(
                            request, response, configuration, getServletContext());
                }
            } else {
                cmd = CommandHandlerEnum.valueOf(command.toUpperCase());
                cmd.execute(
                        request, response, configuration, getServletContext());
            }
        } catch (IllegalArgumentException e) {
            if (Boolean.valueOf(getServletConfig().getInitParameter("debug"))) {
                e.printStackTrace();
                response.reset();
                throw new ServletException(e);
            } else {
                handleError(
                        new ConnectorException(
                                Constants.Errors.CKFINDER_CONNECTOR_ERROR_INVALID_COMMAND, false),
                        configuration, request, response, command);
            }
        } catch (ConnectorException e) {
            if (Boolean.valueOf(getServletConfig().getInitParameter("debug"))
                    && e.getException() != null) {
                e.getException().printStackTrace();
                response.reset();
                throw new ServletException(e.getException());
            } else {
                handleError(e, configuration, request, response, command);
            }
        } catch (Exception e) {
            if (Boolean.valueOf(getServletConfig().getInitParameter("debug"))) {
                e.printStackTrace();
                response.reset();
                throw new ServletException(e);
            } else {
                handleError(new ConnectorException(e), configuration,
                        request, response, command);
            }
        }
    }
    private void checkPostRequest(final HttpServletRequest request)
            throws ConnectorException {
        if (request.getParameter("CKFinderCommand") == null
                || !(request.getParameter("CKFinderCommand").equals("true"))) {
            throw new ConnectorException(
                    Constants.Errors.CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST, true);
        }
    }
    private void handleError(final ConnectorException e,
                             final IConfiguration configuration,
                             final HttpServletRequest request, final HttpServletResponse response,
                             final String currentCommand)
            throws ServletException {
        try {
            if (currentCommand != null) {
                Command command = CommandHandlerEnum.valueOf(
                        currentCommand.toUpperCase()).getCommand();
                if (command instanceof XMLCommand) {
                    CommandHandlerEnum.XMLERROR.execute(request,response, configuration,getServletContext(), e);
                } else {
                    CommandHandlerEnum.ERROR.execute(request, response, configuration,
                            getServletContext(), e);
                }
            } else {
                CommandHandlerEnum.XMLERROR.execute(request, response, configuration,
                        getServletContext(), e);
            }
        } catch (Exception e1) {
            throw new ServletException(e1);
        }
    }
    @Override
    public void init() throws ServletException {
        ServletContextFactory.setServletContext(getServletContext());
        IConfiguration configuration = null;
        try {
            String className = getServletConfig().getInitParameter(
                    "configuration");
            if (className != null) {
                Class<?> clazz = Class.forName(className);
                if (clazz.getConstructor(ServletConfig.class) != null) {
                    configuration = (IConfiguration) clazz.getConstructor(
                            ServletConfig.class).newInstance(getServletConfig());
                } else {
                    configuration = (IConfiguration) clazz.newInstance();
                }
            } else {
                configuration = new Configuration(getServletConfig());
            }
        } catch (Exception e) {
            configuration = new Configuration(getServletConfig());
        }
        try {
            configuration.init();
            AccessControlUtil.getInstance(configuration).loadACLConfig();
        } catch (Exception e) {
            if (Boolean.valueOf(getServletConfig().getInitParameter("debug"))) {
                e.printStackTrace();
            }
            this.startException = e;
            configuration = null;
        }
        ConfigurationFactory.getInstace().setConfiguration(configuration);
    }
    private enum CommandHandlerEnum {
        INIT(new InitCommand()),
        GETFOLDERS(new GetFoldersCommand()),
        GETFILES(new GetFilesCommand()),
        LOADCOOKIES(new LoadCookiesCommand()),
        THUMBNAIL(new ThumbnailCommand()),
        DOWNLOADFILE(new DownloadFileCommand()),
        CREATEFOLDER(new CreateFolderCommand()),
        RENAMEFILE(new RenameFileCommand()),
        RENAMEFOLDER(new RenameFolderCommand()),
        DELETEFOLDER(new DeleteFolderCommand()),
        COPYFILES(new CopyFilesCommand()),
        MOVEFILES(new MoveFilesCommand()),
        DELETEFILES(new DeleteFilesCommand()),
        FILEUPLOAD(new FileUploadCommand()),
        QUICKUPLOAD(new QuickUploadCommand()),
        XMLERROR(new XMLErrorCommand()),
        ERROR(new ErrorCommand());
        private Command command;
        private CommandHandlerEnum(final Command command1) {
            this.command = command1;
        }
        private void execute(final HttpServletRequest request,
                             final HttpServletResponse response, final IConfiguration configuration,
                             final ServletContext sc, final Object... params)
                throws ConnectorException {
            Command com = null;
            try {
                com = command.getClass().newInstance();
            } catch (IllegalAccessException e1) {
                throw new ConnectorException(
                        Constants.Errors.CKFINDER_CONNECTOR_ERROR_INVALID_COMMAND);
            } catch (InstantiationException e1) {
                throw new ConnectorException(
                        Constants.Errors.CKFINDER_CONNECTOR_ERROR_INVALID_COMMAND);
            }
            if (com == null) {
                throw new ConnectorException(
                        Constants.Errors.CKFINDER_CONNECTOR_ERROR_INVALID_COMMAND);
            }
            com.runCommand(request, response, configuration, params);
        }
        public Command getCommand() {
            return this.command;
        }
    }
}